﻿
Imports std

#Const comment = True
#Const include = True
#Const define = False

Public Module _predict
    Public Const start As Char = character.numberMark
    Public Const lineContinue As Char = character.rightSlash
    Public Const lineSeparator As Char = character.newline

    Private Function readline(ByVal script As String, ByRef index As Int64, ByRef line As String) As Boolean
        Dim len As Int64
        len = strlen(script)
        If isemptystring(script) OrElse index >= len Then
            Return False
        Else
            Dim nextline As Int64
            nextline = strindexof(script, lineSeparator, index, 1)
            If nextline = npos Then
                nextline = len
            End If
            line = strmid(script, index, nextline - index)
            kickLeftRightBlank(line)
            index = nextline + strlen(character.newline)
            Return True
        End If
    End Function

    'read a line start with {start}, if have lineContinue at the end, remove it and read next line
    Public Function readPredictLine(ByVal script As String, ByVal name As String, _
                                    ByRef index As Int32, ByRef line As String, _
                                    Optional ByVal start As String = _predict.start) As Boolean
        line = Nothing
        Dim thisline As String = Nothing
        If Not readline(script, index, thisline) Then
            Return False
        End If
        If strstartwith(thisline, start + name) Then
            While strendwith(thisline, lineContinue)
                line += strleft(thisline, strlen(thisline) - strlen(lineContinue))
                If Not readline(script, index, thisline) Then
                    thisline = Nothing
                    Exit While
                End If
            End While
            line += thisline
            Return True
        Else
            Return False
        End If
    End Function

    Public Delegate Sub callback(ByVal line As String, ByRef output As String)

    Public Sub predict(ByVal script As String, ByRef output As String, ByVal name As String, _
                       ByVal cb As callback, Optional ByVal start As String = _predict.start)
        output = Nothing
        Dim index As Int64
        index = 0
        Dim lastindex As Int64
        Dim line As String = Nothing
        Dim len As Int64
        len = strlen(script)
        While index < len
            lastindex = index
            If readPredictLine(script, name, index, line, start) Then
                cb(line, output)
            Else
                output += strmid(script, lastindex, index - lastindex)
            End If
        End While
    End Sub

    Public Sub predict(ByRef script As String)
        Dim last As String = Nothing
        Do
            copy(last, script)
#If comment Then
            comment(script)
#End If
#If include Then
            include(script)
#End If
#If define Then
            define(script)
#End If
        Loop Until strsame(last, script)
    End Sub
End Module
